package ajjj.kiviq;

import java.util.*;
import ajjj.kiviq.entities.*;

/**
 * Performs searches through a list of categories
 * 
 * @author orjohan
 */
public class Search {

    //The results
    private SearchResults results;
    //The categories being searched
    private List<Category> categories;

    /**
     * Initialize the Search with a list
     * of Categories that should be processed
     * during the search
     * 
     * @param categories The Categories that should
     * be searched
     */
    public Search(List<Category> categories) {
        this.categories = categories;
    }

    /**
     * Searches the categories for questions
     * that have titles containing any of the keywords
     * or partial strings passed, case insensitive.
     * The results are sorted by relevance and may be accessed
     * through the getResults() method
     * 
     * @param searchKeywords The keywords to search for,
     * should be words that are separated by spaces.
     * Case insensitive
     * 
     */
    public void doSearch(String searchKeywords) {
        results = new SearchResults();
	if (searchKeywords == null)
	    return;

        searchKeywords = searchKeywords.toLowerCase().replaceAll("[ ]{2,}", " ");
        String[] keywords = searchKeywords.split(" ");
        for (Category c : categories) {
            for (Question q : c.getQuestions()) {		
                List<String> matchedWords = new ArrayList<String>();
                String lowerCaseTitle = q.getTitle().toLowerCase();
                for (String keyword : keywords) {
                    if (lowerCaseTitle.contains(keyword)) {
                        matchedWords.add(keyword);
                    }
                }
                if (!matchedWords.isEmpty()) {
                    String correctAnswer = getCorrectAnswer(q);

                    if (correctAnswer != null) {
                        SearchResult res = new SearchResult(
                                join(matchedWords), q.getTitle(), correctAnswer);
                        res.setRelevance(matchedWords.size());
                        results.add(res);
                    }
                }
            }
        }
        sort();
    }

    /**
     * The results after calling the doSearch() method
     * 
     * @return The results
     */
    public SearchResults getResults() {
        return results;
    }
    
    /**
     * Sorts the results
     */
    private void sort() {
        Collections.sort(results);
    }

    /**
     * Gets the correct answer to a Question,
     * null if there are none (should not be allowed)
     * 
     * @param q The Question to search
     * @return The content string of the correct alternative
     */
    private String getCorrectAnswer(Question q) {
        for (Alternative a : q.getAlternatives()) {
            if (a.isRight()) {
                return a.getContent();
            }
        }
        return null;
    }

    /**
     * Joins the strings of a list to form a
     * single string of keywords
     * 
     * @param list The strings to join
     * @return The resulting string, will be the strings
     * contained in the list separated by spaces
     */
    private String join(List<String> list) {
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            res.append(list.get(i));
            if (i != list.size() - 1) {
                res.append(" ");
            }
        }

        return res.toString();
    }
}
